package com.jt.www.queue.process;

import com.google.common.collect.Maps;
import com.jt.www.admin.user.service.UserService;
import com.jt.www.common.service.MessageService;
import com.jt.www.common.service.SendEmailsService;
import com.jt.www.dao.mapper.issue.EPolicyLogMapper;
import com.jt.www.dao.mapper.issue.EPolicyMapper;
import com.jt.www.dao.mapper.issue.mapper.IssuePolicyLogEntityMapper;
import com.jt.www.dao.mapper.issue.mapper.IssueRecordEntityMapper;
import com.jt.www.dao.mapper.issue.mapper.MqMessageEntityMapper;
import com.jt.www.enums.issue.InvoiceTypeEnum;
import com.jt.www.model.entity.MessageInfoEntity;
import com.jt.www.model.entity.User;
import com.jt.www.model.issue.entity.IssuePolicyLogEntity;
import com.jt.www.model.issue.entity.IssueRecordEntity;
import com.jt.www.model.mail.dto.MailDTO;
import com.jt.www.model.param.endorse.AppDetailProParam;
import com.jt.www.model.pay.ResBindDetailQo;
import com.jt.www.model.pay.ResBindQo;
import com.jt.www.model.reps.GenericDataResponse;
import com.jt.www.model.reps.GenericListResponse;
import com.jt.www.model.vo.endorse.AppDetailProVo;
import com.jt.www.model.vo.sdCheck.ApplicationFormInvoiceVo;
import com.jt.www.model.vo.sdCheck.HolderForProVO;
import com.jt.www.model.vo.sdCheck.PolAttachmentProVO;
import com.jt.www.remote.DexClient;
import com.jt.www.remote.ins.InsClient;
import com.jt.www.util.DateUtils;
import com.jt.www.util.JsonUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * 电子保单和电子发票通用的接口，需要的时候继承他
 */
@Service
public class ElecPolicyProcess extends ElecPolicyProcessAbstract {

    public static final Logger log = LoggerFactory.getLogger(ElecPolicyProcess.class);

    private final static Integer MESSAGE_TYPE = 2;// 投保单
    @Autowired
    IssueRecordEntityMapper issueRecordEntityMapper;
    @Autowired
    EPolicyLogMapper ePolicyLogMapper;
    @Autowired
    EPolicyMapper ePolicyMapper;
    @Autowired
    DexClient dexClient;
    @Autowired
    InsClient insClient;
    @Autowired
    IssuePolicyLogEntityMapper issuePolicyLogEntityMapper;
    @Autowired
    MqMessageEntityMapper mqMessageEntityMapper;
    @Autowired
    ProcessAZBHS processAZBHS;
    @Autowired
    ProcessSD processSD;
    @Autowired
    ProcessEpolicy processEpolicy;
    @Autowired
    ProcessHT processHT;
    @Autowired
    ProcessSP processSP;
    @Autowired
    ProcessSPX processSPX;
    @Autowired
    ProcessSPXTP processSPXTP;
    @Autowired
    ProcessSZAndXZ processSZAndXZ;
    @Autowired
    ProcessSZXZ processSZXZ;
    @Autowired
    ProcessSZXZDD processSZXZDD;
    @Autowired
    ProcessXZ processXZ;
    @Autowired
    ProcessXZXPX processXZXPX;
    @Autowired
    ProcessYNFJ processYNFJ;
    @Autowired
    private SendEmailsService emailsService;
    @Autowired
    private UserService userService;
    @Autowired
    private MessageService messageService;

    @Override
    public Boolean process(Element rootElement, String ifCode) {
        boolean result = true;
        ElecPolicyProcessAbstract elecPolicyProcess = IssuePolicyIfCodeFactory.getProcess(ifCode);
        if (elecPolicyProcess == null) {
            log.error("传入错误if_code : {} ,未匹配到电子保单或者电子发票方法, 当前时间是 {} ", ifCode, DateUtils.toYmdHms(new Date()));
            return true;
        }
        result = elecPolicyProcess.process(rootElement, ifCode);
        return result;
    }

    /**
     * 解析返回报文xml
     *
     * @param rootElement
     * @return
     */
    @Override
    public Element getRespPacket(Element rootElement) {
        Element respPacket = rootElement.element("respPacket");
        Element element = null;
        if (respPacket != null) {
            try {
                element = DocumentHelper.parseText(respPacket.getText()).getRootElement();
            } catch (DocumentException e) {
                e.printStackTrace();
                log.error("xml转义失败，生成xml错误", e);
            }
        }
        return element;
    }

    /*
     * 解析返回请求报文xml
     * @param document 文档对象
     * @return 返回dom元素
     */
    @Override
    public Element getReqPacket(Element rootElement) {
        Element respPacket = rootElement.element("reqPacket");
        Element element = null;
        if (respPacket != null) {
            try {
                element = DocumentHelper.parseText(respPacket.getText()).getRootElement();
            } catch (DocumentException e) {
                e.printStackTrace();
                log.error("xml转义失败，生成xml错误", e);
            }
        }
        return element;
    }

    /**
     * 根据投保单号查询是否已经入库
     *
     * @param appCode
     * @return
     */
    @Override
    public Boolean judgingStorage(String appCode) {
        String currentTime = DateUtils.getCurrentTime();
        IssueRecordEntity issueRecordEntity = new IssueRecordEntity();
        issueRecordEntity.setApplicationFormCode(appCode);
        List<IssueRecordEntity> select = issueRecordEntityMapper.select(issueRecordEntity);
        if (select != null && select.size() > 0) {
            log.info("系统时间：" + currentTime + ", 投保单号是" + appCode + "的消息发送重复");
            // 消息重复，消息直接消费完成。
            return true;
        }
        return false;
    }

    /**
     * 适用于大地保险公司电子保单
     *
     * @param applicationFormCode
     * @param url
     * @return
     */
    @Override
    public String getNewUrl(String applicationFormCode, String url) {
        url = url.replace("/download", "/download/link");
        try {
            try {
                Thread.sleep(80000);
                HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
                connection.setReadTimeout(60000);
                connection.setConnectTimeout(10000);
                connection.setRequestMethod("GET");
                if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream inputStream = connection.getInputStream();
                    StringBuffer tStringBuffer = new StringBuffer();

                    BufferedReader tBufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    String sTempOneLine;
                    while ((sTempOneLine = tBufferedReader.readLine()) != null) {
                        tStringBuffer.append(sTempOneLine);
                    }
                    log.info("大地返回新电子保单路径: {}", tStringBuffer.toString());
                    return tStringBuffer.toString();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            log.error(applicationFormCode + ", 保单原地址为：" + url, e);
        }
        return url;
    }

    /*
     * 绑定资源，更新下载状态
     * @param applicationFormCode 投保单号
     * @param fileId             文件id
     */
    @Override
    public void bindingResources(String applicationFormCode, String fileId, IssuePolicyLogEntity issuePolicyLogEntity) throws Exception {
        String status = issuePolicyLogEntity.getStatus();
        if ("3".equals(status)) {
            issuePolicyLogEntity.setTimes(1);
            issuePolicyLogEntity.setEPolicyId(fileId);
            issuePolicyLogEntity.setStatus("3");
            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
        } else {
            ResBindQo resBindQo = new ResBindQo();
            resBindQo.setApplicationFormCode(applicationFormCode);
            ResBindDetailQo resBindDetailQo = new ResBindDetailQo();
            resBindDetailQo.setBizCodeType("01");
            resBindDetailQo.setResCode("A002");
            resBindDetailQo.setResId(fileId);
            resBindDetailQo.setResName("电子保单、保单影印件");
            List<ResBindDetailQo> list = new ArrayList<>();
            list.add(resBindDetailQo);
            resBindQo.setDetailList(list);
            ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = null;
            try {
                String s = JsonUtils.toJson(resBindQo);
                log.info(DateUtils.getCurrentTime() + "投保单号 " + applicationFormCode + " 调用绑定资源接口开始，入参：" + s);
                genericListResponseResponseEntity = insClient.bindResources(resBindQo);
                GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
                String code = body.getCode();
                log.info(DateUtils.getCurrentTime() + "投保单号 " + applicationFormCode + " 调用绑定资源接口返回结果码" + code + ":" + body.getMsg());
                if (!"0000".equals(code)) {
                    issuePolicyLogEntity.setTimes(1);
                    issuePolicyLogEntity.setEPolicyId(fileId);
                    issuePolicyLogEntity.setStatus("3");
                    issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
                } else {
                    issuePolicyLogEntity.setTimes(1);
                    issuePolicyLogEntity.setEPolicyId(fileId);
                    issuePolicyLogEntity.setStatus("2");
                    issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
                }
            } catch (Exception e) {
                issuePolicyLogEntity.setTimes(1);
                issuePolicyLogEntity.setEPolicyId(fileId);
                issuePolicyLogEntity.setStatus("3");
                issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
                log.error("调用绑定资源接口失败，请重新尝试");
            }
        }
    }

    /**
     * 发送邮件
     *
     * @param tbNo
     * @param type
     */
    @Override
    public void sendEmail(String tbNo, String type) {
        //发送云南非九电子保单邮件
        log.info("--send ynEmail begin--" + tbNo);
        AppDetailProVo detailVos = null;
        ResponseEntity<GenericDataResponse<AppDetailProVo>> appDetailPro;
        AppDetailProParam p = new AppDetailProParam();
        p.setAppCode(tbNo);
        p.setChannelCode("edu");    // 渠道编号
        try {
            appDetailPro = insClient.searchAppDetailPro(p);
            detailVos = appDetailPro.getBody().getData();
            MailDTO mailDTO = new MailDTO();
            HolderForProVO holder = detailVos.getHolder();
            String holderCode = holder.getHolderCode();
            User userholder = userService.findEduUserByCode(holderCode);
            mailDTO.setUserName(userholder.getName());
            mailDTO.setProductName(detailVos.getProductName());
            mailDTO.setEmail(userholder.getEmail());
            mailDTO.setProposalNo(detailVos.getPolicyNo());
            mailDTO.setOrderNo(detailVos.getOrderCode());
            mailDTO.setPolicyNo(Collections.singletonList(tbNo));

            List<PolAttachmentProVO> attachmentList = detailVos.getPolAttachmentList();
            for (PolAttachmentProVO attachment : attachmentList) {
                if ("A002".equals(attachment.getResCode())) {
                    log.info("Search" + tbNo + "policy success");
                    mailDTO.setPolicyId(attachment.getId());
                }
            }

            if (!StringUtils.isEmpty(userholder.getEmail())) {
                emailsService.sendEmail(mailDTO, type);
            }
        } catch (Exception e) {
            log.error("根据投保单号" + tbNo + "查询投保单信息失败" + e);
        }

        log.info("--send ynEmail end--");

        log.info("--create message start-- productName:{},tbNo:{},policyNo:{},holderCode:{}",
                detailVos.getProductName(), tbNo, detailVos.getPolicyNo(), detailVos.getHolder().getHolderCode());
        createMessage(detailVos.getProductName(), tbNo, detailVos.getPolicyNo(), detailVos.getHolder().getHolderCode());
        log.info("--create message end--");
    }

    /**
     * 获取电子发票类型,以及发票信息
     *
     * @param appCode
     * @return
     */
    @Override
    public Map<String, String> getAppcodeInvoiceType(String appCode) {
        Map<String, String> invoices = Maps.newHashMap();
        String invoiceType = InvoiceTypeEnum.PAPER_EXCLUSIVE.getType();
        String bankAddress = ""; //购方开户地址  选填
        String mobile = ""; //购方联系电话  选填
        String bankName = ""; // 购方开户行名称  选填
        String bankNo = ""; //购方银行账户  选填
        AppDetailProVo appDetailProVo = insAppDetailList(appCode);
        List<ApplicationFormInvoiceVo> invoiceVoList = appDetailProVo.getApplicationFormInvoiceVos();
        if (invoiceVoList.size() != 0) {
            for (ApplicationFormInvoiceVo invoiceVoListVo : invoiceVoList) {
                invoiceType = invoiceVoListVo.getInvoiceType();
                bankAddress = invoiceVoListVo.getTaxpayerAddress();
                mobile = invoiceVoListVo.getTaxpayerTelephone();
                bankName = invoiceVoListVo.getOpenBankName();
                bankNo = invoiceVoListVo.getOpenBankNumber();
            }
        }
        invoices.put("invoiceType", invoiceType);
        invoices.put("bankAddress", bankAddress);
        invoices.put("mobile", mobile);
        invoices.put("bankName", bankName);
        invoices.put("bankNo", bankNo);
        return invoices;
    }

    /**
     * 判断金额是否小于10w，10w之内才能开具电子发票
     *
     * @param fee
     * @return
     */
    @Override
    public Boolean judgingTheAmount(String fee) {
        return new BigDecimal(fee).compareTo(new BigDecimal("100000")) == -1;
    }

    /**
     * 出单成功 生成消息
     *
     * @param productName
     * @param tbNo
     * @param policyNo
     * @param holderCode
     */
    @Override
    public void createMessage(String productName, String tbNo, String policyNo, String holderCode) {

        try {

            log.info("出单成功 生成消息 productName:{},tbNo:{},policyNo:{},holderCode:{}", productName, tbNo, policyNo, holderCode);

            MessageInfoEntity entity = new MessageInfoEntity();
            entity.setNoticeState(false);
            entity.setCreateTime(DateUtils.getCurrentTime());
            entity.setMessageTitle("出单成功");
            entity.setMessageContent("您投保的" + productName + "产品（投保单号：" + tbNo + "）已出单成功，保单号为：" + policyNo + ",按照" + productName + "项目（产品）的约定，保险合同成立并生效。");
            entity.setIsDeleted(false);
            entity.setTargetUser(holderCode);
            entity.setMessageType(MESSAGE_TYPE);
            entity.setNoticeType(0);
            entity.setRecordType(1);
            entity.setMessageUrl("/userCenter/insurdetails?data=" + tbNo);
            int num = messageService.addMessageInfo(entity);

            if (num > 0) {
                log.info("生成出单成功消息成功：投保单号{},保单号{},消息内容{}", tbNo, policyNo, entity.getMessageContent());
            } else {
                log.info("生成出单成功消息失败：投保单号{},保单号{}", tbNo, policyNo);
            }
        } catch (Exception e) {
            log.error("生成出单成功消息异常 投保单号{}：，异常信息{}", tbNo, e);
        }
    }

    /**
     * 根据投保单号远程获取详情
     *
     * @param appCode
     * @return
     */
    @Override
    public AppDetailProVo insAppDetailList(String appCode) {
        log.info("query insClient application 开始--" + appCode);
        AppDetailProVo detailVos = null;
        ResponseEntity<GenericDataResponse<AppDetailProVo>> appDetailPro;
        AppDetailProParam p = new AppDetailProParam();
        p.setAppCode(appCode);
        p.setChannelCode("edu");    // 渠道编号
        try {
            appDetailPro = insClient.searchAppDetailPro(p);
            detailVos = appDetailPro.getBody().getData();
        } catch (Exception e) {
            log.error("调用ins服务失败,错误信息:{} 投保单号为:{} ", e, appCode);
            e.printStackTrace();
        }
        return detailVos;
    }

    /**
     * 绑定发票资源，更新下载状态
     *
     * @param applicationFormCode 投保单号
     * @param fileId              文件id
     */
    @Override
    public void bindInvoice(String applicationFormCode, String fileId, IssuePolicyLogEntity issuePolicyLogEntity) throws Exception {
        String status = issuePolicyLogEntity.getStatus();
        ResBindQo resBindQo = new ResBindQo();
        resBindQo.setApplicationFormCode(applicationFormCode);
        ResBindDetailQo resBindDetailQo = new ResBindDetailQo();
        resBindDetailQo.setBizCodeType("02");// todo 电子发票应该写什么？？？  王立波 02
        resBindDetailQo.setResCode("P001");
        resBindDetailQo.setResId(fileId);
        resBindDetailQo.setResName("电子发票");
        List<ResBindDetailQo> list = new ArrayList<>();
        list.add(resBindDetailQo);
        resBindQo.setDetailList(list);
        ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = null;
        genericListResponseResponseEntity = insClient.bindResources(resBindQo);
        GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
        String code = body.getCode();
        log.info(DateUtils.getCurrentTime() + "调用绑定资源接口返回结果码" + code + ":" + body.getMsg());
        if (!"0000".equals(code)) {
            issuePolicyLogEntity.setTimes(1);
            issuePolicyLogEntity.setEPolicyId(fileId);
            issuePolicyLogEntity.setStatus("6");
            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
        } else {
            issuePolicyLogEntity.setTimes(1);
            issuePolicyLogEntity.setEPolicyId(fileId);
            issuePolicyLogEntity.setStatus("2");
            issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
        }
    }

    @Override
    public IssueRecordEntity insertIssueRecordEntity(String tbNo, String policyNo, String proCode, Element reqPacket, Element respPacket, String status, String ifCode, String currentTime) {
        IssueRecordEntity issueRecordEntity = new IssueRecordEntity();
        issueRecordEntity.setApplicationFormCode(tbNo);
        issueRecordEntity.setPolicyNo(policyNo);
        issueRecordEntity.setProCode(proCode);
        issueRecordEntity.setReqPacket(reqPacket.asXML());
        issueRecordEntity.setResPacket(respPacket.asXML());
        issueRecordEntity.setSendStatus("1");
        // 数据中心返回 的投保单状态
        issueRecordEntity.setStatus(status);
        issueRecordEntity.setCreateTime(currentTime);
        issueRecordEntity.setUpdateTime(currentTime);
        issueRecordEntity.setIfCode(ifCode);
        issueRecordEntityMapper.insert(issueRecordEntity);
        return issueRecordEntity;
    }


    @Override
    public IssuePolicyLogEntity insertIssuePolicyLogEntity(String tbNo, String policyNo, String proCode, String status, String ifCode, String currentTime, Element info) {
        IssuePolicyLogEntity issuePolicyLogEntity = new IssuePolicyLogEntity();
        String consumeStatus = "1";
        issuePolicyLogEntity.setApplicationFormCode(tbNo);
        issuePolicyLogEntity.setPolicyNo(policyNo);
        issuePolicyLogEntity.setType("1");
        issuePolicyLogEntity.setStatus(consumeStatus);
        issuePolicyLogEntity.setCreateTime(currentTime);
        issuePolicyLogEntity.setUpdateTime(currentTime);
        issuePolicyLogEntity.setProCode(proCode);
        // 拼装下载报文
        issuePolicyLogEntity.setParam(info.asXML());
        issuePolicyLogEntity.setTimes(0);
        issuePolicyLogEntity.setIfCode(ifCode);
        issuePolicyLogEntityMapper.insert(issuePolicyLogEntity);
        return issuePolicyLogEntity;
    }

    // 出单失败或者重复出单，消息直接消费完成，在入库的逻辑后边。
    @Override
    public Boolean judgingStatus(String status) {
        // 出单失败，消息直接消费完成，在入库的逻辑后边。
        return "3".equals(status) || "4".equals(status);
    }

}
